#include "Container_t.h"
#include <exception>

template<class T>
Container_t<T>::Container_t()
	: m_count(0)
{
	// TODO: implementation
}

template<class T>
Container_t<T>::~Container_t()
{
	// TODO: should be empty?
}

template<class T>
Container_t<T>::Container_t(const Container_t& other)
{
	// Get iterator
	Iterator_t<T>* it = other.iterator();

	// Iterate over elements in container
	for(it->next(); it->hasNext(); it->next())
	{
		// Insert element to container
		insert(it->get());
	}

	// Release iterator
	delete it;

	if(count() != other.count())
		throw "Container_t: copy ctor error";
}

template<class T>
Container_t<T>& Container_t<T>::operator=(const Container_t& other)
{
	if(this != &other)
	{
		removeAll();

		// Get iterator
		Iterator_t<T>* it = other.iterator();

		// Iterate over elements in container
		for(it->next(); it->hasNext(); it->next())
		{
			// Insert element to container
			insert(it->get());
		}

		// Release iterator
		delete it;

		if(count() != other.count())
			throw "Container_t: operator= error";
	}

	return *this;
}

template<class T>
size_t Container_t<T>::count() const
{
	return m_count;
}

template<class T>
T* Container_t<T>::find(const T& value)
{
	// Reset inner iterator
    reset();

    // Get first element
    T* it = next();

    // Iterate over elements in container
    for(size_t i = 0; i < m_count; i++)
    {
        if(*it == value)
			return it;

        it = next();
    }

    // No elem with given value found
    return NULL;
}

template<class T>
void Container_t<T>::insert(T* const elem)
{
	// Concrete implementation: insert after last element
	doAppend(elem, m_count - 1);

	// Increase count
	m_count++;
}

template<class T>
void Container_t<T>::append(T* const elem, int index)
{
	// Check bounds
	if(index >= (int)m_count || index<-1)
		throw "Container_t: index out of bounds";

	// Concrete implementation
	doAppend(elem, index);

	// Increase count
	m_count++;
}

template<class T>
void Container_t<T>::prepend(T* const elem, int index)
{
	// Check bounds
	if(index > (int)m_count || index < 0)
		throw "Container_t: index out of bounds";

	// Concrete implementation: insert before index (Y) == insert after index (Y-1)
	doAppend(elem, index - 1);

	// Increase count
	m_count++;
}

template<class T>
T* Container_t<T>::remove(const T& value)
{
	// Find elem according to given value
	T* elem = find(value);
	if(elem == NULL)
		return NULL;

	// Concrete implementation
	doRemove(value);

	// Decrease count
	m_count--;

	// Return removed elem
	return elem;
}

template<class T>
bool Container_t<T>::removeAndDelete(const T& value)
{
	// Try to remove elem according to given value
	T* elem = remove(value);
	if(elem == NULL)
		return false;
	
	// Elem was removed, delete it
	delete elem;

	return true;
}

template<class T>
void Container_t<T>::removeAll()
{
	// Concrete implementation
	doRemoveAll();

	// Reset count
	m_count = 0;
}

template<class T>
void Container_t<T>::removeAndDeleteAll()
{
	// Concrete implementation
	doRemoveAndDeleteAll();

	// Reset count
	m_count = 0;
}

template<class T>
void Container_t<T>::print() const
{
	// Get iterator
	Iterator_t<T>* it = iterator();

	// Iterate over elements in container
	int i = 0;
	for(it->next(); it->hasNext(); it->next(), i++)
	{
		// Print element
		std::cout<<"Element["<<i<<"] = "<<*it->get()<<std::endl;
	}

	// Release iterator
	delete it;
}